package com.sylvek.sentinel;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.os.AsyncTask;
import android.util.Log;

/**
 * @author sylvek
 * 
 */
public class SentinelClient {
    
    private static final String CHARSET = "UTF-8";
    
    private static final String USER_AGENT = "sentinel-android-01";

    private static final String WS_URL = "https://sentinel-ws.appspot.com/api/";

    private static final GsonBuilder gsonBuilder = new GsonBuilder();

    private static final Gson gson = gsonBuilder.create();

    private static final HttpParams params = new BasicHttpParams();

    private static final DefaultHttpClient client = getThreadSafeClient(params);

    static {
        HttpProtocolParams.setUserAgent(params, USER_AGENT);
        HttpProtocolParams.setContentCharset(params, CHARSET);
        HttpConnectionParams.setConnectionTimeout(params, 30000);
        HttpConnectionParams.setSoTimeout(params, 50000);
    }

    /**
     * Get a threadsafe {@link DefaultHttpClient} using provided params.
     * 
     * @param params {@link HttpParams} to use.
     * @return created {@link DefaultHttpClient}.
     */
    private static DefaultHttpClient getThreadSafeClient(final HttpParams params)
    {
        DefaultHttpClient client = new DefaultHttpClient(params);
        final ClientConnectionManager mgr = client.getConnectionManager();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
        return client;
    }

    public interface OnPostExecute<T> {
        void execute(T result);
    }

    public static class PublishAlert extends AsyncTask<String, Void, Emergency> {
        private final OnPostExecute<Emergency> onPostExecute;

        public PublishAlert(final OnPostExecute<Emergency> onPostExecute)
        {
            this.onPostExecute = onPostExecute;
        }

        @Override
        protected Emergency doInBackground(String... params)
        {
            final HttpPost request = new HttpPost(WS_URL + "alert");
            final List<NameValuePair> formparams = new ArrayList<NameValuePair>();
            formparams.add(new BasicNameValuePair("name", params[0]));
            formparams.add(new BasicNameValuePair("text", params[1]));
            formparams.add(new BasicNameValuePair("latitude", params[2]));
            formparams.add(new BasicNameValuePair("longitude", params[3]));
            formparams.add(new BasicNameValuePair("postAddress", params[4]));

            try {
                request.setEntity(new UrlEncodedFormEntity(formparams, CHARSET));
                final HttpResponse response = client.execute(request);
                if (response.getStatusLine().getStatusCode() == 200) {
                    return gson.fromJson(EntityUtils.toString(response.getEntity()), Emergency.class);
                }
            } catch (ClientProtocolException e) {
            } catch (IOException e) {
            }

            return null;
        }

        @Override
        protected void onPostExecute(Emergency result)
        {
            try {
                this.onPostExecute.execute(result);
            } catch (Exception e) {
                Log.e("SentinelClient", e.getMessage());
            }
        }
    }

    public static class FetchEmergencies extends AsyncTask<String, Void, Emergency[]> {

        private final OnPostExecute<Emergency[]> onPostExecute;

        public FetchEmergencies(final OnPostExecute<Emergency[]> onPostExecute)
        {
            this.onPostExecute = onPostExecute;
        }

        @Override
        protected Emergency[] doInBackground(String... params)
        {
            final HttpGet request = new HttpGet(WS_URL + "alerts?name=" + params[0] + "&latitude=" + params[1] + "&longitude="
                    + params[2]);

            try {
                final HttpResponse response = client.execute(request);
                if (response.getStatusLine().getStatusCode() == 200) {
                    return gson.fromJson(EntityUtils.toString(response.getEntity()), Emergency[].class);
                }
            } catch (ClientProtocolException e) {
            } catch (IOException e) {
            }

            return new Emergency[0];
        }

        @Override
        protected void onPostExecute(Emergency[] result)
        {
            try {
                this.onPostExecute.execute(result);
            } catch (Exception e) {
                Log.e("SentinelClient", e.getMessage());
            }
        }
    }

    public static class PushLocation extends AsyncTask<String, Void, Integer> {

        private final OnPostExecute<Integer> onPostExecute;

        public PushLocation(final OnPostExecute<Integer> onPostExecute)
        {
            this.onPostExecute = onPostExecute;
        }

        @Override
        protected Integer doInBackground(String... params)
        {
            final HttpPost request = new HttpPost(WS_URL + "location?age=300000" /* 15min */);
            final List<NameValuePair> formparams = new ArrayList<NameValuePair>();
            formparams.add(new BasicNameValuePair("name", params[0]));
            formparams.add(new BasicNameValuePair("latitude", params[1]));
            formparams.add(new BasicNameValuePair("longitude", params[2]));

            try {
                request.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8"));
                final HttpResponse response = client.execute(request);
                if (response.getStatusLine().getStatusCode() == 200) {
                    return gson.fromJson(EntityUtils.toString(response.getEntity()), Integer.class);
                }
            } catch (ClientProtocolException e) {
            } catch (IOException e) {
            }

            return null;
        }

        @Override
        protected void onPostExecute(Integer result)
        {
            try {
                this.onPostExecute.execute(result);
            } catch (Exception e) {
                Log.e("SentinelClient", e.getMessage());
            }
        }
    }
}
